home *** CD-ROM | disk | FTP | other *** search
-
- /*
- * atari_serial.h: Common definitions for all Atari serial ports
- *
- * Copyright 1994 Roman Hodek
- * EMail: rnhodek@cip.informatik.uni-erlangen.de (Internet)
- * or: Roman_Hodek@n.maus.de (MausNet, NO mail > 16 KB!)
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file README.legal in the main directory of this archive
- * for more details.
- *
- */
-
-
- #ifndef _ATARI_SERIAL_H
- #define _ATARI_SERIAL_H
-
- #include <linux/tty.h>
-
- /* 4 is sufficient for now... */
- #define NR_PORTS 4
-
-
- /* Structure describing one bit in a register that may be high- or
- * low-active. This is used for RI detection, because the location of
- * this signal varies widely. The function TEST_BITPOS() is provided
- * to return the status of such a bit.
- */
-
- typedef struct {
- volatile unsigned char *addr; /* address of register */
- unsigned char bitno; /* bit#, 0..7 */
- unsigned char active_state; /* 1 for high-active,
- * 0 for * low-active */
- } BITPOS;
-
- static __inline__ int TEST_BITPOS( BITPOS bp )
-
- {
- return( !bp.addr ? 0 :
- !!(*(bp.addr) & (1 << bp.bitno)) == bp.active_state );
- }
-
-
- /* Atari serial port types are numbered from 100 to avoid interference
- * with the PC types (1..4)
- */
- typedef enum {
- SCC_NORM = 100, /* standard SCC channel */
- SCC_DMA, /* SCC channel with DMA support */
- MFP_CTRL, /* standard MFP port with modem control signals */
- MFP_BARE, /* MFP port without modem controls */
- } SERTYPE;
-
- /* This function tables does the abstraction from the underlying
- * hardware:
- *
- * init(): Initialize the port as necessary, set RTS and DTR and
- * enable interrupts. It does not need to set the speed and other
- * parameters, because change_speed() is called, too.
- * deinit(): Stop the port (wait for all characters to be sent,
- * disable interrupts)
- * enab_tx_int(): Enable or disable the Tx Buffer Empty interrupt
- * independantly from other interrupt sources. The pointer to
- * this function may be NULL, if there is no way to do this or it
- * is too complex. This Tx ints are just disabled to save some
- * interrupts if the transmitter is stopped anyway.
- * check_custom_divisor(): Check the given custom divisor for legality
- * and return 0 if OK, non-zero otherwise.
- * change_speed(): Set port speed, character size, number of stop
- * bits and parity from the termios structure. If the user wants
- * to set the speed with a custom divisor, he is required to
- * check the baud_base first!
- * restart(): Is called every time new data arrived in the Tx queue
- * and may be used to restart the transmitter if it ran empty.
- * 'c' is the first character to be output or -1 if there is
- * none. If more than one character can be written (FIFOs!), you
- * have to take the remaining ones from the write queue directly.
- * This function is called with interrupts off.
- * throttle(): Set or clear the RTS line according to 'status'.
- * set_break(): Set or clear the 'Send a Break' flag.
- * get_serial_info(): Fill in the baud_base and custom_divisor
- * fields of a serial_struct. It may also modify other fields, if
- * needed.
- * get_modem_info(): Return the status of RTS, DTR, DCD, RI, DSR and CTS.
- * set_modem_info(): Set the status of RTS and DTR according to
- * 'new_dtr' and 'new_rts', resp. 0 = clear, 1 = set, -1 = don't change
- * ioctl(): Process any port-specific ioctl's. This pointer may be
- * NULL, if the port has no own ioctl's.
- *
- */
-
- struct async_struct;
-
- typedef struct {
- void (*init)( struct async_struct *info );
- void (*deinit)( struct async_struct *info, int leave_dtr );
- void (*enab_tx_int)( struct async_struct *info, int enab_flag );
- int (*check_custom_divisor)( struct async_struct *info, int divisor );
- void (*change_speed)( struct async_struct *info );
- void (*restart)( struct async_struct *info, int c );
- void (*throttle)( struct async_struct *info, int status );
- void (*set_break)( struct async_struct *info, int break_flag );
- void (*get_serial_info)( struct async_struct *info,
- struct serial_struct *retinfo );
- unsigned int (*get_modem_info)( struct async_struct *info );
- int (*set_modem_info)( struct async_struct *info, int new_dtr,
- int new_rts );
- int (*ioctl)( struct tty_struct *tty, struct file *file,
- struct async_struct *info, unsigned int cmd,
- unsigned long arg );
- } SERIALSWITCH;
-
-
- /* This is a modified version of the PC-Linux async_struct. Mainly,
- * stuff like port address, xmit_fifo_size and the like are left out
- * and other information fields were added.
- */
-
- struct async_struct {
- /* Atari specific fields */
- SERTYPE type; /* UART type */
- volatile void *base; /* base address */
- BITPOS RI; /* Where the Ring Indicator is signalled */
- SERIALSWITCH *sw; /* functions to manage this port */
- /* common fields */
- int flags;
- struct tty_struct *tty;
- int timeout;
- int custom_divisor;
- int x_char; /* xon/xoff characater */
- int close_delay;
- int event;
- int line;
- int count; /* # of fd on device */
- int blocked_open; /* # of blocked opens */
- long session; /* Session of opening process */
- long pgrp; /* pgrp of opening process */
- struct termios normal_termios;
- struct termios callout_termios;
- struct wait_queue *open_wait;
- struct wait_queue *close_wait;
- struct wait_queue *xmit_wait;
- };
-
- /*
- * Events are used to schedule things to happen at timer-interrupt
- * time, instead of at rs interrupt time.
- */
- #define RS_EVENT_READ_PROCESS 0
- #define RS_EVENT_WRITE_WAKEUP 1
- #define RS_EVENT_HANGUP 2
- #define RS_EVENT_BREAK 3
- #define RS_EVENT_OPEN_WAKEUP 4
-
-
-
- /***************************** Prototypes *****************************/
-
- void rs_stop( struct tty_struct *tty );
- void rs_start( struct tty_struct *tty );
- void rs_write( struct tty_struct * tty );
- void rs_throttle( struct tty_struct * tty, int status );
- void rs_hangup( struct tty_struct *tty );
- int rs_open( struct tty_struct *tty, struct file * filp );
- long rs_init( long kmem_start );
-
- /************************* End of Prototypes **************************/
-
-
-
- /*************************** Inline Functions *************************/
-
-
- #include <linux/interrupt.h>
- #include <asm/bitops.h>
-
- /*
- * This routine is used by the interrupt handler to schedule
- * processing in the software interrupt portion of the driver.
- * It is needed in the port-specific interrupt handlers, so it is
- * declared here in the common header.
- */
-
- extern char rs_event[];
-
- static inline void rs_sched_event( struct async_struct *info, int event )
-
- {
- info->event |= 1 << event;
- set_bit(info->line, rs_event);
- mark_bh(SERIAL_BH);
- }
-
-
- /* The following functions do common tasks needed in the interrupt
- * service routine(s):
- *
- * - Putting a character into the read_queue, either with or without
- * an error condition, and waking up processes waiting for
- * something to arrive
- * - Check if a throttle is needed due to the read queue getting full
- * - Removing a character from the write queue, obeying pending flow
- * control characters
- * - Checking for enough characters in the write queue to wake up
- * sleeping processes
- * - Doing required actions on wait queues if DCD has changed
- * - Doing required actions on wait queues if CTS has changed;
- * returns non-zero, if the transmitter should be restarted
- */
-
- static __inline__ void rs_put_char_to_queue( struct async_struct *info,
- int c, int err )
-
- { struct tty_queue *q = &info->tty->read_q;
-
- if (!FULL(q)) {
-
- if (err) {
- if (err == TTY_BREAK)
- rs_sched_event( info, RS_EVENT_BREAK );
-
- /* ignore parity errors if parity checking isn't enabled. */
- if (!(err == TTY_PARITY && !I_INPCK(info->tty))) {
- set_bit( q->head, &info->tty->readq_flags );
- c = err;
- }
- }
-
- q->buf[q->head] = c;
- INC(q->head);
-
- rs_sched_event( info, RS_EVENT_READ_PROCESS );
- }
- }
-
-
- static __inline__ void rs_rx_throttle_if_needed( struct async_struct *info )
-
- { struct tty_queue *q = &info->tty->read_q;
-
- if (LEFT(q) < RQ_THRESHOLD_LW &&
- !set_bit( TTY_RQ_THROTTLED, &info->tty->flags))
-
- rs_throttle( info->tty, TTY_THROTTLE_RQ_FULL );
- }
-
-
- static __inline__ int rs_get_char_from_queue( struct async_struct *info )
-
- { int ch;
- struct tty_queue *q = &info->tty->write_q;
-
- if (info->x_char) {
- ch = info->x_char;
- info->x_char = 0;
- }
- else if (!EMPTY(q)) {
- ch = q->buf[q->tail];
- INC(q->tail);
- }
- else {
- rs_stop( info->tty );
- ch = -1;
- }
-
- return( ch );
- }
-
-
- static __inline__ void rs_tx_wakeup_if_needed( struct async_struct *info )
-
- { struct tty_queue *q = &info->tty->write_q;
-
- if (LEFT(q) > WAKEUP_CHARS) {
- rs_sched_event( info, RS_EVENT_WRITE_WAKEUP );
- if (info->tty->write_data_cnt) {
- set_bit( info->tty->line, &tty_check_write );
- mark_bh( TTY_BH );
- }
- }
- }
-
-
- static __inline__ void rs_dcd_changed( struct async_struct *info, int dcd )
-
- {
- if (!C_CLOCAL(info->tty)) {
-
- if (dcd)
- rs_sched_event( info, RS_EVENT_OPEN_WAKEUP );
- else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) &&
- (info->flags & ASYNC_CALLOUT_NOHUP)))
- rs_sched_event( info, RS_EVENT_HANGUP );
- }
- }
-
-
- static __inline__ int rs_cts_changed( struct async_struct *info, int cts )
-
- {
- if (!C_CRTSCTS(info->tty) || (info->flags & ASYNC_CLOSING))
- return( 0 );
-
- if (info->tty->hw_stopped) {
- if (cts) {
- info->tty->hw_stopped = 0;
- rs_start( info->tty );
- return( 1 );
- }
- }
- else {
- if (!cts) {
- info->tty->hw_stopped = 1;
- rs_stop( info->tty );
- }
- }
-
- return( 0 );
- }
-
-
- #endif /* _ATARI_SERIAL_H */
-